package com.life.ai.server.framework.osssts;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.life.ai.server.common.exception.ServiceException;
import com.life.ai.server.common.utils.RedisCacheUtil;
import com.life.ai.server.common.utils.RedisUtils;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

/**
 * OssStsManager
 *
 * @author kylewka
 * @since 2023/8/2
 */
@Data
@Slf4j
@Component
@SuppressWarnings("all")
public class OssStsClient implements ApplicationRunner {

    private final static String STS_KEY = "sts_token:";

    /**
     * STS配置信息
     */
    private OssStsProperties ossStsProperties;

    /**
     * 单例STS客户端
     */
    private volatile IAcsClient client;

    public OssStsClient(OssStsProperties ossStsProperties) {
        Assert.notNull(ossStsProperties.getAccessKeyId(), "accessKeyId not be blank");
        Assert.notNull(ossStsProperties.getAccessKeySecret(), "accessKeySecret not be blank");
        Assert.notNull(ossStsProperties.getRoleArn(), "roleArn not be blank");
        Assert.isTrue(ossStsProperties.getDuration().compareTo(ossStsProperties.getCacheDuration()) > 0,
                "STS: 缓存时长需小于有效期");
        this.ossStsProperties = ossStsProperties;
    }

    /**
     * 单例STS客户端初始化方法
     *
     * @return IAcsClient
     */
    public IAcsClient client() {
        if (client == null) {
            synchronized (OssStsClient.class) {
                if (client == null) {
                    DefaultProfile profile = DefaultProfile.getProfile(ossStsProperties.getRegionId(),
                            ossStsProperties.getAccessKeyId(), ossStsProperties.getAccessKeySecret());
                    client = new DefaultAcsClient(profile);
                }
            }
        }
        return client;
    }

    /**
     * 请求获取STS-token
     *
     * @return AssumeRoleResponse
     */
    @SneakyThrows
    public StsCredentials getAcsResponse(String roleSessionName) {
        AssumeRoleRequest request = ossStsProperties.assumeRoleRequest(roleSessionName);
        AssumeRoleResponse.Credentials credentials = client().getAcsResponse(request).getCredentials();
        return new StsCredentials(credentials, ossStsProperties.getCacheDuration());
    }

    /**
     * 初始化Sts-token
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        try {
            long start = System.currentTimeMillis();
            String roleName = ossStsProperties.getRoleName();
            StsCredentials credentials = getAcsResponse(roleName);
            RedisUtils.set(STS_KEY + roleName, credentials, ossStsProperties.getCacheDuration());
            log.info("STS初始化完成用时 {}ms", (System.currentTimeMillis() - start));
        } catch (Exception e) {
            log.error("初始化直传STS失败，请检查配置信息");
//            throw e;
        }
    }

    public StsCredentials getStsCredentials() {
        try {
            String roleName = ossStsProperties.getRoleName();
            return RedisCacheUtil.query(STS_KEY + roleName, roleName,
                    this::getAcsResponse, ossStsProperties.getCacheDuration());
        } catch (Exception e) {
            log.error("直传token获取失败", e);
            throw new ServiceException("直传token获取失败");
        }
    }
}
